<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<HTML>
<HEAD>
<meta name="GENERATOR" content="Microsoft&reg; HTML Help Workshop 4.1">
<Title>Custom Serializers</Title><link rel="STYLESHEET" type="text/css" href="styles.css">
</HEAD>
<BODY>
<h1>Custom Serializers</h1>

Any non-trivial web service will require you to handle complex types. There are two basic approachs in pocketSOAP for
working with complex types, you can use serializers that map between SOAP complex types and objects within your system, 
or you can work with the node objects and collections directly. 

<h2>Sample complex type</h2>

The Apache SOAP project includes a sample called the addressbook sample, in this it defines a complex type for a phone number
and a complex type for an address, which includes a phone number. Here's an example of an instance of the address type.

<pre class="sample">
&lt;address&gt;
	&lt;number&gt;100&lt;/number&gt;
	&lt;street&gt;Spear Street&lt;/street&gt;
	&lt;city&gt;San Francisco&lt;/city&gt;
	&lt;state&gt;CA&lt;/state&gt;
	&lt;zip&gt;94107&lt;/zip&gt;
	&lt;phone&gt;
		&lt;area&gt;415&lt;/area&gt;
		&lt;exchange&gt;343&lt;/exchange&gt;
		&lt;number&gt;3000&lt;/number&gt;
	&lt;/phone&gt;
&lt;/address&gt;
</pre>


<h2>Map the complex type to objects</h2>

Rather than using the Node objects as detailed in an earlier section, you want to to serialize and deserialize from SOAP directly into
application specific objects, to do this you need to write custom serializer and deserializer objects [or use the property bag serializer].
<BR><BR>
First off, let define a VB class for the address &amp; phone types, lets keep things simple, and just use public member variables
<pre class="sample">
address.cls
Option Explicit

Public number As String
Public street As String
Public city As String
Public state As String
Public zip As String

Public phone As telephone

Private Sub Class_Initialize()
    Set phone = New telephone
End Sub

phone.cls
Option Explicit

Public area As String
Public exchange As String
Public number As String
</pre>

Now, lets write some code that create's one of these and sets up the values, and then passes it to pocketSOAP
<pre class="sample">
dim adr 
set adr    = CreateObject("samples.address")
adr.number = "100"
adr.street = "Spear Street"
adr.city   = "San Francisco"
adr.state  = "CA"
adr.zip    = "94107"
adr.phone.area     = "415"
adr.phone.exchange = "343"
adr.phone.number   = "3000"

dim env 
set env = CreateObject("pocketSOAP.Envelope.2")
env.SetMethod "addAddress", "http://address.example.org/"
env.Parameters.Create "address", adr
</pre>

<h2>Serializers</h2>

Now, pocketSOAP know's nothing about our address object, or how it should be serialized, so lets write a serializer, this should take an instance of an address
object and generate the SOAP/XML representation for it.
<pre class="sample">
addrserializer.cls
Option Explicit

Implements ISoapSerializer

Private Sub ISoapSerializer_Serialize(V As Variant, _
                                        ByVal ctx As PocketSOAP.ISerializerContext, _
                                        ByVal dest As PocketSOAP.ISerializerOutput)
										
    ' pocketSOAP will call us at the point it wants the address object serializing out, 
    ' V will contain the address object instance to serialize
    ' in turn, all we do is ask it to serialize the child items for us
	
    dest.SerializeValue V.number, "number", ""
    dest.SerializeValue V.street, "street", ""
    dest.SerializeValue V.city,   "city",   ""
    dest.SerializeValue V.state,  "state",  ""
    dest.SerializeValue V.zip,    "zip",    ""
    dest.SerializeValue V.phone,  "phone",  ""
End Sub
</pre>

Now that last line ask pocketSOAP to serialize a phone object, so we'll need to write a serializer for that as well
<pre class="sample">
phoneserializer.cls
Option Explicit

Implements ISoapSerializer

Private Sub ISoapSerializer_Serialize(V As Variant, _
                                        ByVal ctx As PocketSOAP.ISerializerContext, _
                                        ByVal dest As PocketSOAP.ISerializerOutput)
										
    ' pocketSOAP will call us at the point it wants the phone object serializing out, 
    ' V will contain the phone object instance to serialize
    ' in turn, all we do is ask it to serialize the child items for us
	
    dest.SerializeValue V.area, 	"area", 	""
    dest.SerializeValue V.exchange, "exchange", ""
    dest.SerializeValue V.number,   "number",   ""
End Sub
</pre>

Finally, we need to tell pocketSOAP that it can use these serializers to serializer instances of the address &amp; phone objects.
<pre class="sample">
....
dim env 
set env = CreateObject("pocketSOAP.Envelope.2")
env.SerializerFactory.Serializer "{AC02D0F2-A2A1-4cba-8589-5E4CC2250D81}", "address", "http://address.example/org", "samples.addrserializer"
env.SerializerFactory.Serializer "{870C6692-F3C1-4684-B1AE-47B6ED81604C}", "phone",   "http://address.example/org", "samples.phoneserializer"
env.SetMethod "addAddress", "http://address.example.org/"
env.Parameters.Create "address", adr
</pre>

Now, pocketSOAP uses Interface ID's to regognise particular objects, if you're not a COM programmer, then that might not make any sense, 
Once you build the project with the address &amp; phone objects in, you'll be able to find the Interface ID's from the resulting DLL. Run oleview
select file->view typelib and open the DLL you've just built. Looking at the library file, you'll see a list of all the properies on the object, 
something like
<pre class="sample">
    [
      odl,
      <b>uuid(0B451395-7AFF-44E8-BF88-CF35FB1A34D6)</b>,
      version(1.0),
      hidden,
      dual,
      nonextensible,
      oleautomation,
      custom(50867B00-BB69-11D0-A8FF-00A0C9110059, 4)    

    ]
    interface _address : IDispatch {
        [id(0x40030000), propget]
        HRESULT number([out, retval] BSTR* number);
        [id(0x40030000), propput]
        HRESULT number([in] BSTR number);
        [id(0x40030001), propget]
        HRESULT street([out, retval] BSTR* street);
        [id(0x40030001), propput]
        HRESULT street([in] BSTR street);
        [id(0x40030002), propget]
        HRESULT city([out, retval] BSTR* city);
        [id(0x40030002), propput]
        HRESULT city([in] BSTR city);
        [id(0x40030003), propget]
        HRESULT state([out, retval] BSTR* state);
        [id(0x40030003), propput]
        HRESULT state([in] BSTR state);
        [id(0x40030004), propget]
        HRESULT zip([out, retval] BSTR* zip);
        [id(0x40030004), propput]
        HRESULT zip([in] BSTR zip);
        [id(0x40030005), propget]
        HRESULT phone([out, retval] _phone** phone);
        [restricted] void Missing18();
        [id(0x40030005), propputref]
        HRESULT phone([in] _phone* phone);
    };
	</pre>
The long number in the uuid section is the Interface ID, copy this into your call to Serializer, and repeat for the phone object.	

<BR><BR>
That's it, you're all set, if you add a final line to your application code, <b>wscript.echo e.serialize</b> and run it, pocketSOAP will
serialize the envelope, get to the one parameter we added, match the object to the serializer we registered, call the serializer which
serializes the address and phone number out to XML.<BR><BR>

<p>In many cases, VB uses may prefer to use the propertybag serializer, which doesn't need specific interface ID's to use.</p>

<p>As of pocketSOAP 1.2, the serializerFactory maintains a pool of created serializers, that can be re-used during the [de]serialization
process. In this case the serializerFactory will create a single instance of the serializer and make multiple calls to the Serialize function.
In the case of the de-serialization process, the deserializer should release all its resources when End is called, once End has been called,
the de-serializer is returned to the pool, and it may be asked to de-serialize further items, by start getting called again.</p>

<p>Its highly recommended that if you're going to use either a custom serializer or the propertybag serializer, that you define interfaces to your
objects in IDL, and compile them to a typelibrary, and have your VB objects implement the particular interfaces. This gives you much more
control over interface versioning, whereas if you leave it to VB, it can and will change the interface ID's on you, breaking the code that
maps in your serializers. The full scope on COM for VB programs is way out of scope for pocketSOAP, i'd highly recommend you look at a good
COM/VB book such as Ted Patison's excellent 
<a href="http://www.amazon.com/exec/obidos/ASIN/073561010X/qid=1005200975/sr=8-1/ref=sr_8_19_1/002-6786985-7992830" target="_blank">Programming Distributed Applications with COM+ and Microsoft Visual Basic 6.0</a> 
</p>
<BR><BR><BR>
<h3>Copyright</h3>
<p>Copyright &copy; Simon Fell, 2000-2004. All rights reserved.<br>

</BODY>
</HTML>
